(ns conducta.ui.swing
 (:use (conducta ui)))
(import '(org.fest.swing.fixture JTextComponentFixture JButtonFixture 
          ItemGroupFixture TextDisplayFixture TextInputFixture
          StateVerificationFixture FocusableComponentFixture
          KeyboardInputSimulationFixture MouseInputSimulationFixture JCheckBoxFixture
          JRadioButtonFixture JToggleButtonFixture TwoStateButtonFixture
          JTabbedPaneFixture JListFixture JListItemFixture JSpinnerFixture 
          JSliderFixture))
(import '(org.fest.swing.core KeyPressInfo MouseButton))
(import '(org.fest.swing.util Modifiers))
(import '(javax.swing KeyStroke))

(import '(org.conducta.ui.swing.fixture JRadioButtonGroupFixture JCheckBoxGroupFixture))

(defn label 
  ([window] {:parent window :name "label" :fixture (.label window) })
  ([window name] {:parent window :name name :fixture (.label window name) })
)

(defn combo 
  ([window] {:parent window :name "combo" :fixture (.comboBox window) })
  ([window name] {:parent window :name name :fixture (.comboBox window name) })  
)

(defn text 
  ([window] {:parent window :name "text" :fixture (.textBox window)})
  ([window name] {:parent window :name name :fixture (.textBox window name)}))

(defn button 
  ([window] {:parent window :name "button" :fixture (.button window)})
  ([window name] {:parent window :name name :fixture (.button window name)})
)

(defn radio 
  ([window] {:parent window :name name :fixture (.radioButton window)})
  ([window name] {:parent window :name name :fixture (.radioButton window name)}) 
)

(defn toggle 
  ([window] {:parent window :name name :fixture (.toggleButton window)})
  ([window name] {:parent window :name name :fixture (.toggleButton window name)})
)

(defn checkbox 
  ([window] {:parent window :name "checkbox" :fixture (.checkBox window)})
  ([window name] {:parent window :name name :fixture (.checkBox window name)})
)

(defn list-selector 
  ([window] {:parent window :name "list" :fixture (.list window)})
  ([window name] {:parent window :name name :fixture (.list window name)})
)

(defn scroll-bar 
  ([window] {:parent window :name "scroll-bar" :fixture (.scrollBar window)})
  ([window name] {:parent window :name name :fixture (.scrollBar window name)})
)

(defn dialog 
  ([window] {:parent window :name "dialog" :fixture (.dialog window)}) 
  ([window name] {:parent window :name name :fixture (.dialog window name)})
)

(defn file-chooser
  ([window] {:parent window :name name :fixture (.fileChooser window)})
  ([window name] {:parent window :name name :fixture (.fileChooser window name)})
)

(defn spinner 
  ([window] {:parent window :name "spinner" :fixture (.spinner window)}) 
  ([window name] {:parent window :name name :fixture (.spinner window name)})
)

(defn scroll-pane 
  ([window] {:parent window :name "scroll-pane" :fixture (.scrollPane window)})
  ([window name] {:parent window :name name :fixture (.scrollPane window name)})
)

(defn slider 
  ([window] {:parent window :name "slider" :fixture (.slider window)}) 
  ([window name] {:parent window :name name :fixture (.slider window name)})
)

(defn split-pane 
  ([window] {:parent window :name "split-pane" :fixture (.splitPane window)}) 
  ([window name] {:parent window :name name :fixture (.splitPane window name)})
)

(defn tabbed-pane 
  ([window] {:parent window :name "tabbed-pane" :fixture (.tabbedPane window)})
  ([window name] {:parent window :name name :fixture (.tabbedPane window name)}) 
 )

(defn table 
  ([window] {:parent window :name "table" :fixture (.table window)}) 
  ([window name] {:parent window :name name :fixture (.table window name)})
)

(defn tree 
  ([window] {:parent window :name "tree" :fixture (.tree window)}) 
  ([window name] {:parent window :name name :fixture (.tree window name)})
)

(defn toolbar 
  ([window] {:parent window :name "toolbar" :fixture (.toolbar window)}) 
  ([window name] {:parent window :name name :fixture (.toolbar window name)})
)

(defn menu-item [window name] {:parent window :name name :fixture (.menuItem window name)})
(defn menu-item-by-path [window path] {:parent window :name path :fixture 
                                       (.menuItemWithPath window (into-array path))})

;; utilities to help manage component groups
(defn radio-button-group [buttons] {:fixture (JRadioButtonGroupFixture. (into-array buttons))})

;; Text input
(defmethod enter-text TextInputFixture [text {widget :fixture}] (.enterText widget text))
(defmethod delete-text TextInputFixture [{widget :fixture}] (.deleteText widget))
(defmethod select-text TextInputFixture [text {widget :fixture}] (.select widget text))
(defmethod select-all TextInputFixture [{widget :fixture}] (.selectAll widget))
(defmethod select-range TextInputFixture [start end {widget :fixture}] (.selectText widget start end))

(defmethod enter-text JSpinnerFixture [text {widget :fixture}] (.enterText widget text))
(defmethod enter-text JSliderFixture [value {widget :fixture}] (.slideTo widget (Integer/parseInt value)))

;; Text display
(defmethod verify-text! TextDisplayFixture [text {widget :fixture}] (.requireText widget text))
(defmethod read-text TextInputFixture [{widget :fixture}] (.text widget))

;; Group items
(defmethod select ItemGroupFixture [option {widget :fixture}] (.selectItem widget option))
(defmethod verify-selected! ItemGroupFixture [option {widget :fixture}] (.requireSelection widget option))
(defmethod verify-not-selected! ItemGroupFixture [{widget :fixture}] (.requireNoSelection widget))

;; State verification
(defmethod verify-enabled! StateVerificationFixture [{widget :fixture}] (.requireEnabled widget))
(defmethod verify-disabled! StateVerificationFixture [{widget :fixture}] (.requireDisabled widget))
(defmethod verify-visible! StateVerificationFixture [{widget :fixture}] (.requireVisible widget))
(defmethod verify-invisible! StateVerificationFixture [{widget :fixture}] (.requireNotVisible widget))

;; Key input 
(defmethod type-key KeyboardInputSimulationFixture [key-letter {widget :fixture}]
  (def keystroke (KeyStroke/getKeyStroke key-letter))
  (.pressAndReleaseKey widget (.modifiers 
                               (KeyPressInfo/keyCode  (.getKeyCode keystroke )) 
                               (Modifiers/keysFor (.getModifiers keystroke ))) )
)

(defmethod press-key KeyboardInputSimulationFixture [key-letter {widget :fixture}]
  (def buf (StringBuilder. "pressed "))
  (.pressKey widget (.getKeyCode (KeyStroke/getKeyStroke (str (.append buf (first key-letter))))))
)

(defmethod release-key  KeyboardInputSimulationFixture [key-letter {widget :fixture}] 
  (def buf (StringBuilder. "released "))
  (.releaseKey widget (.getKeyCode (KeyStroke/getKeyStroke (str (.append buf (first key-letter))))))
)

;; Mouse input
(defmethod click MouseInputSimulationFixture [{widget :fixture}] (.click widget))
(defmethod double-click MouseInputSimulationFixture [{widget :fixture}] (.doubleClick widget))
(defmethod right-click MouseInputSimulationFixture [{widget :fixture}] (.rightClick widget))
(defmethod left-click MouseInputSimulationFixture [{widget :fixture}] (.click widget MouseButton/LEFT_BUTTON))
(defmethod middle-click MouseInputSimulationFixture [{widget :fixture}] (.click widget MouseButton/MIDDLE_BUTTON))


;; Items that toggle state
(defmethod verify-selected! TwoStateButtonFixture [option {widget :fixture}] (.requireSelected widget option))
(defmethod verify-not-selected! TwoStateButtonFixture [{widget :fixture}] (.requireNotSelected widget))

;; Check boxes
(defmethod select JCheckBoxFixture [{widget :fixture}] (.check widget))
(defmethod unselect JCheckBoxFixture [{widget :fixture}] (.uncheck widget))

;; Toggle buttons
(defmethod select JToggleButtonFixture [{widget :fixture}] (.check widget))
(defmethod unselect JToggleButtonFixture [{widget :fixture}] (.uncheck widget))

;; Varitions of select
(defmethod select JRadioButtonGroupFixture [option {widget :fixture}] (.click (.findByText widget option)))
(defmethod select JListFixture [item {widget :fixture}] (.select (.item widget item)))
(defmethod select JSpinnerFixture [value {widget :fixture}] (.enterText widget value))
(defmethod select JSliderFixture [value {widget :fixture}] (.slideTo widget (Integer/parseInt value)))
(defmethod select JTabbedPaneFixture [option {widget :fixture}] (.selectTab widget option))

(defmethod drag-item JListFixture [text {widget :fixture}] (.drag widget text))
(defmethod drop-item JListFixture 
  ([{widget :fixture}] (.drop widget))
  ([position {widget :fixture}] (.drop widget position)) 
)
